import { Object3D, Vector3 } from 'three-legacy';
import Base from '../cmd-common/base';
import {
  BasicSurfaceMode,
  MouseState,
  ReferencePlaneType,
  State,
  TrackingData,
} from '../type';
import { nextmeshEventCenter } from '@app-nextmesh/common/events/EventCenter';
import {
  CadScene,
  CENTEREVENTS,
  CSCircle,
  CSLine,
  CSys,
  EventsRes,
  MathTool,
  SceneGraph,
  SceneSetup,
} from '@amcax/base';
import { ctx2 } from '@app-base/module';
import { documentV2 } from '@app-nextmesh/domain';
export default class CmdInteractor extends Base {
  planeType: string;
  planeNormal: Vector3;
  csys: CSys;
  planeOrigin: Vector3;
  private cadScene: CadScene;
  private sceneSetup: SceneSetup;
  private assisGroup: Object3D;
  startPoint: Vector3;
  endPoint: Vector3;
  height: number = 0;
  radius: number;
  previewLine: TrackingData;
  planeInfoMap: Map<string, any>;
  centerCoord: number[];
  lineColor = 0x1890f5; // 线条颜色
  stepStatus: MouseState;
  constructor(normal: string) {
    super();
    this.planeType = normal;
    this.init();
  }

  init() {
    // 默认xoy 平面
    this.planeNormal = new Vector3(0, 0, 1);
    this.planeOrigin = new Vector3(0, 0, 0);
    this.cadScene = ctx2.cadScene as CadScene;
    this.sceneSetup = ctx2.viewer.sceneSetup;
    this.assisGroup = this.cadScene.assisGroup;
    this.stepStatus = State.NONE;
    this.startPoint = new Vector3(0, 0, 0);
    this.endPoint = new Vector3(0, 0, 0);
    this.previewLine = {
      circle1: null,
      circle2: null,
      rline: null,
      hline: null,
      rlabel: null,
    };
    this.planeInfoMap = new Map([
      [
        ReferencePlaneType.XOY,
        {
          planeNormal: new Vector3(0, 0, 1),
        },
      ],
      [
        ReferencePlaneType.XOZ,
        {
          planeNormal: new Vector3(0, 1, 0),
          centerPoint: new Vector3(
            this.startPoint.x,
            this.height,
            this.startPoint.z,
          ),
          vertexVec: [
            new Vector3(this.endPoint.x, 0, this.endPoint.z),
            new Vector3(this.endPoint.x, this.height, this.endPoint.z),
          ],
        },
      ],
      [
        ReferencePlaneType.YOZ,
        {
          planeNormal: new Vector3(1, 0, 0),
          centerPoint: new Vector3(
            this.height,
            this.startPoint.y,
            this.startPoint.z,
          ),
          vertexVec: [
            new Vector3(0, this.endPoint.y, this.endPoint.z),
            new Vector3(this.height, this.endPoint.y, this.endPoint.z),
          ],
        },
      ],
    ]);
    this.registerEvents();

    this.updatePlane(this.planeType);
  }
  destroy() {
    this.unregisterEvents();
    this.releaseObjects();
    this.reset();
  }

  registerEvents() {
    nextmeshEventCenter()
      .setState('topo-sphere')
      .on(CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(CENTEREVENTS.POINTERUP, this.onMouseUp)
      .on(CENTEREVENTS.KEYUP, this.onKeyUp);
  }
  unregisterEvents = () => {
    nextmeshEventCenter()
      .off(CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(CENTEREVENTS.POINTERUP, this.onMouseUp)
      .off(CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy)
      .setDefault();
  };
  onMouseMove = (e: EventsRes) => {
    if (this.stepStatus === State.NONE) {
      this.startPoint = this.sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        this.planeNormal,
        this.planeOrigin,
      );
      this.csys = MathTool.createCsysFromPlacement([
        [this.startPoint.x, this.startPoint.y, 0],
        [0, 0, 1],
        [1, 0, 0],
      ]);
    }
    if (this.stepStatus === State.DRAW) {
      this.endPoint = this.sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        this.planeNormal,
        this.planeOrigin,
      );
      this.radius = this.startPoint.clone().sub(this.endPoint).length();
      this.showPreview();
    }
  };
  async finshDraw() {
    // 球心
    const centerCoord = this.startPoint?.toArray();
    const params = {
      mode: BasicSurfaceMode.Sphere,
      source: [centerCoord],
      param: [this.radius],
    };
    await documentV2.basicPlaneShape(params);
  }
  onMouseUp = async (e: EventsRes) => {
    if (e.button.onLeft) {
      if (this.stepStatus == State.NONE) {
        this.stepStatus = State.DRAW;
        return;
      }
      if (this.stepStatus === State.DRAW) {
        this.finshDraw();
        return;
      }
    } else {
      this.releaseObjects();
      this.reset();
    }
  };

  showPreview() {
    switch (this.planeType) {
      case ReferencePlaneType.XOY:
        this.csys = MathTool.createCsysFromPlacement([
          [this.startPoint.x, this.startPoint.y, 0],
          [0, 0, 1],
          [1, 0, 0],
        ]);

        break;
      case ReferencePlaneType.XOZ:
        this.csys = MathTool.createCsysFromPlacement([
          [this.startPoint.x, 0, this.startPoint.z],
          [0, 1, 0],
          [1, 0, 0],
        ]);

        break;
      case ReferencePlaneType.YOZ:
        this.csys = MathTool.createCsysFromPlacement([
          [0, this.startPoint.y, this.startPoint.z],
          [1, 0, 0],
          [0, 1, 0],
        ]);
        break;
      default:
        return;
    }
    if (this.stepStatus === State.DRAW) {
      if (!this.previewLine.circle1) {
        this.previewLine.circle1 = new CSCircle({
          center: this.startPoint,
          radius: this.radius,
          csys: this.csys,
          lineWidth: 4,
          color: this.lineColor,
        });
        this.previewLine.circle1.addTo(this.assisGroup);
      } else {
        this.previewLine.circle1.update({
          radius: this.radius,
        });
      }
      if (!this.previewLine.rline) {
        this.previewLine.rline = new CSLine({
          vertexs: [this.startPoint, this.endPoint],
          dashed: true,
          color: this.lineColor,
          lineWidth: 3,
        });
        this.previewLine.rline.addTo(this.assisGroup);
      } else {
        this.previewLine.rline.setVertexs([this.startPoint, this.endPoint]);
      }
    }

    ctx2.viewer.requestRender();
  }

  addExit(exitFunc: () => void) {
    this.exitFunc = exitFunc;
  }
  updatePlane(normal: string) {
    this.planeType = normal;
    const planeInfo = this.planeInfoMap.get(this.planeType);
    if (planeInfo) {
      this.planeNormal = planeInfo.planeNormal;
    }
    this.releaseObjects();
    this.reset();
  }
  releaseObjects() {
    this.assisGroup.clear();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }

  reset() {
    this.startPoint = null;
    this.endPoint = null;
    this.height = null;
    this.stepStatus = State.NONE;
    this.previewLine = {
      circle1: null,
      circle2: null,
      rline: null,
      hline: null,
      rlabel: null,
    };
  }
}
